﻿/****************************************************************************
**
* @Project : Frameworks
* @File: aggregate.h
* @Description: 插件管理器核心类头文件，负责插件加载、对象池管理和系统配置
* @Copyright: Copyright (c) 2014
* @Company:
* @WebSite: http://www.zchx.com/
* @author:
* @Revision History
* <pre>
* ----------------------------------------------------------------------
*   Ver     Date       Who        Comments
* ----- ----------  --------  ------------------------------------------
*   1.0  2013/08/12    yeguoxiong      FOR QT 5.1.0
* ----------------------------------------------------------------------
**
* @note 中文注释：插件系统的核心管理器，处理插件生命周期、对象注册和依赖管理
*       English: Core manager of plugin system, handling plugin lifecycle, object registration and dependency management
****************************************************************************/


#ifndef EXTENSIONSYSTEM_PLUGINMANAGER_H
#define EXTENSIONSYSTEM_PLUGINMANAGER_H

#include "extensionsystem_global.h"
#include "aggregate.h"

#include <QObject>
#include <QReadWriteLock>
#include <QStringList>

QT_BEGIN_NAMESPACE
class QTextStream;
class QSettings;
QT_END_NAMESPACE

namespace ExtensionSystem {
class PluginCollection;

namespace Internal {
class PluginManagerPrivate;
}

class IPlugin;
class PluginSpec;

typedef QList<PluginSpec *> PluginSpecSet;

/**
 * @class PluginManager
 * @brief 插件管理器核心类
 * @details 负责插件的加载、初始化、卸载和对象池管理，实现单例模式确保全局唯一
 *          提供类型安全的对象查询接口，支持插件间通信和系统配置管理
 *          作为整个插件系统的中枢，协调所有插件的生命周期和交互
 *          // TODO: Qt5.15.2升级 - 考虑使用QScopedPointer管理内部状态
 */
class EXTENSIONSYSTEM_EXPORT PluginManager : public QObject
{
    Q_OBJECT

public:
    /**
     * @brief 获取单例实例
     * @return PluginManager唯一实例指针
     * @details 实现线程安全的单例模式，确保系统中只有一个插件管理器实例
     *          // TODO: Qt5.15.2升级 - 考虑使用std::call_once优化单例初始化
     */
    static PluginManager *instance();

    /**
     * @brief 构造函数
     * @details 初始化插件管理器内部状态和私有实现
     *          创建对象池和插件集合的初始状态
     *          // TODO: Qt5.15.2升级 - 检查是否需要初始化额外的Qt 5.15.2特性
     */
    PluginManager();
    
    /**
     * @brief 析构函数
     * @details 清理插件资源，卸载所有已加载插件
     *          释放对象池和内部管理结构
     */
    virtual ~PluginManager();
    
    /*-------------------------------------------
    * Object pool operations
    ---------------------------------------------*/
    /**
     * @brief 添加对象到全局对象池
     * @param obj 要添加的对象指针
     * @details 将对象注册到系统，使其可被其他插件查询和使用
     *          触发objectAdded信号通知系统
     *          // TODO: Qt5.15.2升级 - 添加空指针检查
     */
    static void addObject(QObject *obj);
    
    /**
     * @brief 从全局对象池移除对象
     * @param obj 要移除的对象指针
     * @details 从系统中注销对象，触发aboutToRemoveObject信号
     *          确保对象被安全移除，避免悬垂指针
     *          // TODO: Qt5.15.2升级 - 添加空指针检查
     */
    static void removeObject(QObject *obj);
    
    /**
     * @brief 获取对象池中的所有对象
     * @return 所有已注册对象的列表
     * @details 返回对象池的快照，不影响实际对象生命周期
     */
    static QList<QObject *> allObjects();

    /**
     * @brief 查询指定类型的所有对象
     * @tparam T 要查询的对象类型
     * @return 匹配类型的对象列表
     * @details 遍历对象池，使用query_all进行类型安全查询
     *          // C++17升级 - 考虑使用std::optional返回值优化
     */
    template <typename T> static QList<T *> getObjects()
    {
        QReadLocker lock(&m_instance->m_lock);
        QList<T *> results;
        QList<QObject *> all = allObjects();
        QList<T *> result;
        foreach (QObject *obj, all)
        {
            result = ExtensionSystem::query_all<T>(obj);
            if (!result.isEmpty())
            {
                results += result;
            }
        }
        return results;
    }

    /**
     * @brief 查询指定类型的首个对象
     * @tparam T 要查询的对象类型
     * @return 匹配类型的对象指针，若不存在则返回nullptr
     * @details 按顺序查找第一个匹配类型的对象
     *          // TODO: Qt5.15.2升级 - 将0替换为nullptr
     *          // C++17升级 - 考虑使用std::optional返回值优化
     */
    template <typename T> static T *getObject()
    {
        QReadLocker lock(&m_instance->m_lock);
        QList<QObject *> all = allObjects();
        T *result = nullptr; // TODO: Qt5.15.2升级 - 已替换0为nullptr
        foreach (QObject *obj, all)
        {
            if ((result = ExtensionSystem::query<T>(obj)) != nullptr)
                break;
        }
        return result;
    }

    /**
     * @brief 按名称查询对象
     * @param name 对象名称
     * @return 匹配名称的对象指针，若不存在则返回nullptr
     * @details 通过对象的objectName属性进行查找
     */
    static QObject *getObjectByName(const QString &name);
    
    /**
     * @brief 按类名查询对象
     * @param className 类名称
     * @return 匹配类名的对象指针，若不存在则返回nullptr
     * @details 使用metaObject()->className()进行类型匹配
     */
    static QObject *getObjectByClassName(const QString &className);
    
    /*-------------------------------------------
    * Plugin operations
    ---------------------------------------------*/
    /**
     * @brief 获取插件加载队列
     * @return 插件规范对象列表
     * @details 按照依赖关系排序的插件加载顺序
     */
    static QList<PluginSpec *> loadQueue();
    
    /**
     * @brief 加载所有插件
     * @details 按照插件依赖关系和路径配置加载插件，处理插件初始化
     *          触发pluginLoaded信号通知系统
     *          // TODO: Qt5.15.2升级 - 添加错误处理和加载状态反馈
     */
    static void loadPlugins();
    
    /**
     * @brief 获取插件搜索路径
     * @return 插件路径字符串列表
     * @details 系统将在这些路径中查找可用插件
     */
    static QStringList pluginPaths();
    
    /**
     * @brief 设置插件搜索路径
     * @param paths 新的插件路径列表
     * @details 覆盖当前的插件搜索路径
     *          // TODO: Qt5.15.2升级 - 添加路径有效性检查
     */
    static void setPluginPaths(const QStringList &paths);
    
    /**
     * @brief 获取所有插件规范
     * @return 插件规范对象列表
     * @details 包括已加载和未加载的所有插件信息
     */
    static QList<PluginSpec *> plugins();
    
    /**
     * @brief 获取插件集合映射
     * @return 插件集合哈希表（键为集合名称）
     * @details 按集合名称组织的插件分组
     */
    static QHash<QString, PluginCollection *> pluginCollections();
    
    /**
     * @brief 设置插件文件扩展名
     * @param extension 扩展名（不含点）
     * @details 指定插件文件的扩展名，默认为"dll"(Windows)或"so"(Linux)
     */
    static void setFileExtension(const QString &extension);
    
    /**
     * @brief 获取插件文件扩展名
     * @return 当前插件扩展名
     */
    static QString fileExtension();
    
    /**
     * @brief 检查是否有插件加载错误
     * @return 若存在错误则返回true，否则返回false
     */
    static bool hasError();
    
    /*-------------------------------------------
    * Settings
    ---------------------------------------------*/
    /**
     * @brief 设置插件设置对象
     * @param settings QSettings指针
     */
    static void setSettings(QSettings *settings);
    
    /**
     * @brief 获取插件设置对象
     * @return QSettings指针
     */
    static QSettings *settings();
    
    /**
     * @brief 设置全局设置对象
     * @param settings QSettings指针
     */
    static void setGlobalSettings(QSettings *settings);
    
    /**
     * @brief 获取全局设置对象
     * @return QSettings指针
     */
    static QSettings *globalSettings();
    
    /**
     * @brief 写入插件设置
     * @details 将当前插件状态和配置写入设置对象
     */
    static void writeSettings();
    
    /*-------------------------------------------
    * command line arguments
    ---------------------------------------------*/
    /**
     * @brief 获取命令行参数
     * @return 参数字符串列表
     */
    static QStringList arguments();
    
    /**
     * @brief 解析命令行选项
     * @param args 参数列表
     * @param appOptions 应用程序选项映射
     * @param foundAppOptions 找到的选项结果
     * @param errorString 错误信息输出
     * @return 解析成功返回true，否则返回false
     */
    static bool parseOptions(const QStringList &args,const QMap<QString, bool> &appOptions,
                             QMap<QString, QString> *foundAppOptions,QString *errorString);
    
    /**
     * @brief 格式化选项帮助文本
     * @param str 输出文本流
     * @param optionIndentation 选项缩进量
     * @param descriptionIndentation 描述缩进量
     */
    static void formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation);
    
    /**
     * @brief 格式化插件选项帮助文本
     * @param str 输出文本流
     * @param optionIndentation 选项缩进量
     * @param descriptionIndentation 描述缩进量
     */
    static void formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation);
    
    /**
     * @brief 格式化插件版本信息
     * @param str 输出文本流
     */
    static void formatPluginVersions(QTextStream &str);

    /**
     * @brief 获取序列化的命令行参数
     * @return 序列化后的参数字符串
     */
    static QString serializedArguments();

    /**
     * @brief 输出性能分析报告
     * @param what 报告内容描述
     * @param spec 关联的插件规范（可选）
     */
    static void profilingReport(const char *what, const PluginSpec *spec = 0);

signals:
    /**
     * @brief 对象添加信号
     * @param obj 新增的对象
     * @details 当对象被添加到对象池时发射
     */
    void objectAdded(QObject *obj);
    
    /**
     * @brief 对象即将移除信号
     * @param obj 即将移除的对象
     * @details 当对象即将从对象池移除时发射
     */
    void aboutToRemoveObject(QObject *obj);

    /**
     * @brief 插件变化信号
     * @details 当插件加载状态变化时发射
     */
    void pluginsChanged();
    
public slots:
    /**
     * @brief 关闭插件管理器
     * @details 卸载所有插件并清理资源
     */
    void shutdown();
    
private:
    Internal::PluginManagerPrivate *d; ///< 私有实现指针
    static PluginManager *m_instance; ///< 单例实例指针
    // TODO: Qt5.15.2升级 - 单例实例应使用std::unique_ptr管理以避免内存泄漏
    mutable QReadWriteLock m_lock; ///< 多线程同步锁

    friend class Internal::PluginManagerPrivate;
};

} // namespace ExtensionSystem

#endif // EXTENSIONSYSTEM_PLUGINMANAGER_H
